
// --xuezhen--
//rvcpu-test.cpp
#include <verilated.h> 
#include <verilated_vcd_c.h> 
#include <iostream>
#include <fstream>
// #include "Vrvcpu.h"
#include "Vysyx_210184.h"

#define Vrvcpu Vysyx_210184


// #define TRACE_PC


#define CLK_CYCLE   4
#define CLK_POSEDGE 2

#define MEM_DELAY 70



#define UART_BASE 0x10000000 // RT-Thread
#define UART_NUM  8         // The number of UART's Bytes of RT-Thread
// #define UART_BASE 0x80200000 // AM
#define MTIME     0x200bff8// RT_thread
#define MTIMECMP  0x2004000  // RT_thread 0x80200010

#define ROM_ADDR 33554432//13129328+10//131072

using namespace std;

static Vrvcpu* top;
static VerilatedVcdC* tfp;
static vluint64_t main_time = 0;
// static const vluint64_t sim_time = 999999;//999999999;
// static const vluint64_t sim_time = 49999;//999999999;
// static const vluint64_t sim_time = 69999999;
static const vluint64_t sim_time = 29999999;
// static const vluint64_t sim_time = 199999999;//6123;//9;//;99;
// static const vluint64_t sim_time = 999999999;//6123;//9;//;99;

// inst.bin
// inst 0: 1 + zero = reg1 1+0=1
// inst 1: 2 + zero = reg1 2+0=2
// inst 2: 1 + reg1 = reg1 1+2=3
unsigned long int inst_rom[ROM_ADDR];

void read_inst( char* filename)
{
  FILE *fp = fopen(filename, "rb");
  if( fp == NULL ) {
		printf( "Can not open this file!\n" );
		exit(1);
  }
  
  fseek(fp, 0, SEEK_END);
  size_t size = ftell(fp);
  fseek(fp, 0, SEEK_SET);
  size = fread(inst_rom, size, 1, fp);
  fclose(fp);
}



unsigned long int inst_flash[ROM_ADDR];
void read_falsh( char* filename)
{
  FILE *fp = fopen(filename, "rb");
  if( fp == NULL ) {
		printf( "Can not open this file!\n" );
		exit(1);
  }
  
  fseek(fp, 0, SEEK_END);
  size_t size = ftell(fp);
  fseek(fp, 0, SEEK_SET);
  size = fread(inst_flash, size, 1, fp);
  fclose(fp);
}

int main(int argc, char **argv)
{
	// char filename[100] = "../testvector/testcopy.bin";
	// char filename[100] = "../testvector/test.bin";
	// char filename[1000] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/am-kernels/tests/am-tests/build/amtest-riscv64-mycpu.bin";

	// char filename[1000] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/add-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/addi-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/addiw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/addw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/and-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/andi-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/auipc-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/beq-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/bge-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/bgeu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/blt-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/bltu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/bne-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/jal-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/jalr-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lb-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lbu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/ld-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lh-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lhu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lui-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/lwu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/or-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/ori-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sb-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sd-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sh-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/simple-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sll-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/slli-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/slliw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sllw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/slt-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/slti-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sltiu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sltu-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sra-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/srai-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sraiw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sraw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/srl-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/srli-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/srliw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/srlw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sub-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/subw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/sw-riscv64-mycpu.bin";
	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/xor-riscv64-mycpu.bin";

	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/YSYX/oscpu-framework/cpu/riscv-tests/build/xori-riscv64-mycpu.bin";
	// char filename[100] = "../riscv-tests/build/add-riscv64-mycpu.bin";
	// char filename[100] = "../am-kernels/tests/cpu-tests/build/add-riscv64-mycpu.bin";
	// printf("Please enter your filename~\n");
	// cin >> filename;

	// char filename[100] = "/mnt/c/Users/gwbei/Desktop/rt-thread/bsp/qemu-riscv-virt64/rtthread.bin";
	// read_inst(filename);




	// char flashname[1000] = "/mnt/c/Users/gwbei/Desktop/YSYX_SOC_TEST/oscpu-framework/cpu/testvector/hello-flash.bin";
	// char flashname[1000] = "/mnt/c/Users/gwbei/Desktop/ysyxSoC/ysyx/bin/memtest-flash.bin";
	// char flashname[1000] = "/mnt/c/Users/gwbei/Desktop/ysyxSoC/ysyx/program/bin/flash/rtthread-flash.bin";
	// char flashname[1000] = "/mnt/c/Users/gwbei/Desktop/ysyxSoC/ysyx/program/bin/loader/hello-loader.bin";
	// char flashname[1000] = "/mnt/c/Users/gwbei/Desktop/ysyxSoC/ysyx/program/bin/loader/memtest-loader.bin";
	char flashname[1000] = "/mnt/c/Users/gwbei/Desktop/ysyxSoC/ysyx/program/bin/loader/rtthread-loader.bin";
	read_falsh(flashname);
	// std::cout << inst_rom[0x3d1>>2] << std::endl;
	// for(int i=0x488; i<=0x488+10*4; i+=4) std::cout << inst_rom[i>>2] << std::endl;

	
	// initialization
	Verilated::commandArgs(argc, argv);
	Verilated::traceEverOn(true);

	top = new Vrvcpu;
	tfp = new VerilatedVcdC;

	// if_stage = top->if_stage;

	top->trace(tfp, 99);
	tfp->open("top.vcd");
		
		long int pc_hist[4] = {0,0,0,0};
		long int pc_hist_count = 0;
		int is_stop = 0;
		int mem_access_delay = 5;
		long unsigned int mtime = 0;
		long unsigned int mtimecmp = 0;
		int               mtime_div = 0;
		int               mtime_intr = 0;
		long unsigned int uart_register = (33UL<<40) + 10;
		long unsigned int uart_register_divisor = 0;
		char uart_send_data[1000] = "help\nmemcheck\nmemtrace\nlist_fd\nls\npwd\nlist_thread\nlist_device\nversion\nps\n";

		int uart_send_data_count = 0;

		int mem_read_state = 0;
		int mem_write_state = 0;

		int axi4_slave_r_addr_ok = 0;
		long unsigned int axi4_slave_r_addr = 0;

		int axi4_slave_w_addr_ok = 0;
		long unsigned int axi4_slave_w_addr = 0;
		int axi4_slave_w_data_ok = 0;
		long unsigned int axi4_slave_w_data = 0;
		long unsigned int axi4_slave_w_mask = 0;




		// long unsigned int reg_addr;
		// long unsigned int addr;

#ifdef TRACE_PC
		ofstream pc_file;
		pc_file.open("../../pc_in_sim.txt");
#endif
		while( !Verilated::gotFinish() && main_time < sim_time )
		{
			if( main_time % CLK_CYCLE == 0 ) top->clock = 0;
			if( main_time % CLK_CYCLE == CLK_POSEDGE ) top->clock = 1;

#ifdef TRACE_PC
			if(top->mac_ok & (main_time % CLK_CYCLE == CLK_POSEDGE)){
				pc_file << top->pc_o;
				pc_file << "\n"; 
			}
#endif
			if(main_time > 9999999) top->io_interrupt = 0;
			else top->io_interrupt = 0;

			// if(top->mac_ok == 0) std::cout << "MEIE On" << std::endl;

			// if( reg_addr == 0x800005d4 ) std::cout << "Next Addr: " << top->addr_axi4 << " Main Time: " << main_time << std::endl;
			// reg_addr = top->addr_axi4;
			// if( main_time >= 5287006 ) std::cout << "Next Addr: " << top->addr_axi4 << " Main Time: " << main_time << " w ena " << (int)(top->w_ena_axi4) << std::endl;
			// if( top->addr_axi4 == 0x8001e060 && top->r_ena_axi4 == 1) std::cout << "Read Addr: " << top->addr_axi4 << " Main Time: " << main_time << " ROM " << inst_rom[(top->addr_axi4-0x80000000) >> 3] << std::endl;
			// if( top->addr_axi4 == 0x8001e060 && top->w_ena_axi4 == 1) std::cout << "Write Addr: " << top->addr_axi4 << " Main Time: " << main_time << " ROM " << inst_rom[(top->addr_axi4-0x80000000) >> 3] << std::endl;

			// if(mtime > mtimecmp) mtime_intr = 1;
			// else mtime_intr = 0;
			// top->mtime_intr = mtime_intr;


			top->io_master_arready = 1;
			top->io_master_rlast = 1;
			top->io_master_wready = 1;
			top->io_master_awready = 1;

			if( main_time < 10 ){
				top->reset = 1;
			}
			else
			{
				top->reset = 0;
				
				if( main_time % CLK_CYCLE == (CLK_POSEDGE)){

					if(((top->io_master_awaddr-2147483648) >> 3) >= ROM_ADDR && (top->io_master_arvalid == 1 | top->io_master_awvalid)) {
						if((((top->io_master_awaddr)>=UART_BASE && (top->io_master_awaddr)<(UART_BASE+UART_NUM)) || (top->io_master_awaddr)==MTIME || (top->io_master_awaddr)==MTIMECMP) && (top->io_master_awvalid)) {

						}
						else if((((top->io_master_araddr)>=UART_BASE && (top->io_master_araddr)<(UART_BASE+UART_NUM)) || (top->io_master_araddr)==MTIME || (top->io_master_araddr)==MTIMECMP) && (top->io_master_arvalid)) {

						}
						else if( (top->io_master_araddr >= 0x30000000) && (top->io_master_araddr <= 0x3fffffff) && top->io_master_arvalid ) {

						}
						else{
							std::cout << "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW " << main_time  << " " << (top->io_master_araddr) << " " << top->io_master_awaddr << " valid: " << top->io_master_arvalid << " " << top->io_master_awvalid << std::endl;
							// std::cout << "0x2b390: " << inst_rom[(0x2b390>>3)]<< std::endl;

							break;
						}

					// std::cout << "1: "<< inst_rom[(0x9000-16-8)>>2] << std::endl;
					// std::cout << inst_rom[(0x9000-16-8+4)>>2] << std::endl;
					}


					// if(top->io_master_araddr < 0x80000000 && top->io_master_arvalid ){
					// 	std::cout << "RRRRRRRRRRRRRRRRR " << main_time  << " " << (top->io_master_araddr) << " " << std::endl;
					// 	break;
					// }
					// else if( top->io_master_araddr > 0x8fffffff && top->io_master_arvalid ){
					// 	std::cout << "RRRRRRRRRRRRRRRRR " << main_time  << " " << (top->io_master_araddr) << " " << std::endl;
					// 	break;
					// }

					// if(top->io_master_awaddr < 0x80000000 && top->io_master_awvalid){
					// 	std::cout << "WWWWWWWWWWWWWWWWWW " << main_time  << " " << top->io_master_awaddr << " " << int(top->io_master_wstrb) << std::endl;
					// 	break;
					// }
					// else if(top->io_master_awaddr > 0x8fffffff && top->io_master_awvalid){
					// 	std::cout << "WWWWWWWWWWWWWWWWWW " << main_time  << " " << top->io_master_awaddr << " " << int(top->io_master_wstrb) << std::endl;
					// 	break;
					// }



					if(top->io_master_arvalid == 1) {
						axi4_slave_r_addr = top->io_master_araddr;
						axi4_slave_r_addr_ok = 1;
						mem_read_state = axi4_slave_r_addr_ok;
					}

					if(top->io_master_awvalid == 1) {
						axi4_slave_w_addr = top->io_master_awaddr;
						axi4_slave_w_addr_ok =1;
						// if(axi4_slave_w_addr_ok==1 && axi4_slave_w_data_ok==1) mem_write_state = 1;
					}
					if(top->io_master_wvalid == 1) {
						unsigned long int mask_tmp = 0;
						unsigned long int power_of_16 = 1;
						int count = 0;
						axi4_slave_w_data_ok = 1;
						axi4_slave_w_data = top->io_master_wdata;
						mask_tmp = top->io_master_wstrb;
						axi4_slave_w_mask = 0;
						while(count < 8){
							if(mask_tmp%2==1) axi4_slave_w_mask += 255UL * power_of_16;
							mask_tmp = mask_tmp >> 1;
							count++;
							power_of_16 *= 256UL;
						}
						// if(axi4_slave_w_addr == 0x8001e09c){
						// 	std::cout << axi4_slave_w_data << " " << main_time << std::endl;
						// }
						
						// if(axi4_slave_w_addr_ok==1 && axi4_slave_w_data_ok==1) mem_write_state = 1;
					}
					if(axi4_slave_w_addr_ok==1 && axi4_slave_w_data_ok==1) mem_write_state = 1;

					if(mem_read_state == 1) {
						if(mem_access_delay == 0){
							if(axi4_slave_r_addr==MTIMECMP){
								top->io_master_rdata = mtimecmp;
								// std::cout << "READ mtiemcmp: " << mtimecmp << " mian_time: " << main_time << std::endl; 
							}
							else if(axi4_slave_r_addr==MTIME){
								top->io_master_rdata = mtime;
								// std::cout << "READ mtiem: " << mtime << std::endl; 
							}
							else if( axi4_slave_r_addr>=UART_BASE && axi4_slave_r_addr<UART_BASE+UART_NUM ){
								unsigned long int offset = axi4_slave_r_addr - UART_BASE;
								if(offset == 0){
									if( (uart_register>>(3*8))%256 >=128 ) top->io_master_rdata = uart_register_divisor;
									else{
										if(uart_send_data[uart_send_data_count] != '\0'){
											// if(uart_send_data[uart_send_data_count] == 'l'){
											// 	std::cout << "\n\n\nprint: l at main time: " << main_time << std::endl;
											// }
											top->io_master_rdata = uart_send_data[uart_send_data_count++];
										}
										else{
											uart_send_data_count = 0;
											top->io_master_rdata = uart_send_data[uart_send_data_count++];
										}
									} 
								}
								else top->io_master_rdata = uart_register;
								// if(offset == 5) std::cout << uart_register << std::endl;
								// std::cout << "UART READ: " << offset << std::endl;
							}
							else if(axi4_slave_r_addr>=0x30000000 && axi4_slave_r_addr<=0x3fffffff){
								top->io_master_rdata = inst_flash[ (axi4_slave_r_addr-0x30000000) >> 3 ];
							}
							else{
								unsigned int addr = axi4_slave_r_addr-2147483648 ;
								addr = addr >> 3;
								if(addr < ROM_ADDR && addr >=0) top->io_master_rdata = inst_rom[addr];
								else top->io_master_rdata = 0;
							}
							
							mem_access_delay = MEM_DELAY;
							mem_read_state = 0;
							axi4_slave_r_addr_ok = 0;
							top->io_master_rvalid = 1;
						}
						else{
							top->io_master_rvalid = 0;
							mem_access_delay -= 1;
						}
						// std::cout << "Handle read" << std::endl;
					}
					else if(mem_write_state == 1){
						unsigned long int tmp;
						unsigned long int mask;
						if(mem_access_delay == 0){
							if(axi4_slave_w_addr>=UART_BASE && axi4_slave_w_addr<UART_BASE+UART_NUM){
								char ch;
								unsigned long int offset = axi4_slave_w_addr - UART_BASE;
								// std::cout << "UART W: " << offset << std::endl;
								// unsigned long int mask = 0xff;

								if(offset == 0){
									if( (uart_register>>(3*8))%256 >=128 ) uart_register_divisor = (axi4_slave_w_data) % 256;
									else{
										ch = (axi4_slave_w_data) % 256;
										// std::cout << "Main Time: " << main_time << std::endl;
										// std::cout << "UART Data: " << (int)ch << std::endl;
										// std::cout << "UART Char: " << ch << std::endl;
										// std::cout << "UART END" << std::endl;
										std::cout << ch ;
									}
								}
								else{									
									mask = axi4_slave_w_mask;
									mask = ~mask;
									tmp = uart_register & mask;
									// std::cout << tmp << std::endl;
									tmp = tmp | (axi4_slave_w_data&(~mask));
									// std::cout << tmp << std::endl;
									uart_register = tmp;
								}							

								// std::cout << uart_register << " offset " << offset << " mask " <<  top->w_mask_axi4_64 << " data " << top->w_data_axi4 << std::endl;
							}
							else if(axi4_slave_w_addr==MTIMECMP){
								std::cout << "WRITE mtimecmp, original date: " << mtimecmp;
								mtimecmp = axi4_slave_w_data;
								std::cout << " ,write data: " << mtimecmp << std::endl;
							}
							else if(axi4_slave_w_addr==MTIME){
								mtime = axi4_slave_w_data;
							}
							else{
								mask = axi4_slave_w_mask;
								mask = ~mask;
								tmp = inst_rom[(axi4_slave_w_addr-2147483648) >> 3] & mask;
								tmp = tmp | ((axi4_slave_w_data)&(~mask));
								inst_rom[(axi4_slave_w_addr-2147483648) >> 3] = tmp;
								// if(axi4_slave_w_addr == 0x8001e09c){
								// 	std::cout << "0x8001e09c: " << tmp << " " << mask <<" " << axi4_slave_w_mask << " " << axi4_slave_w_data << " " << main_time<< std::endl; 
								// 	// break;
								// }
							}
							top->io_master_bvalid = 1;
							mem_access_delay = MEM_DELAY;
							mem_write_state = 0;
							axi4_slave_w_addr_ok = 0;
							axi4_slave_w_data_ok = 0;
						}
						else{
							// if((top->addr_axi4)>=UART_BASE && (top->addr_axi4)<=UART_BASE+UART_NUM){
							// 	std::cout << "UART x Addr: " << top->addr_axi4 << " Main Time: " << main_time << std::endl;
							// 	std::cout << "UART x Data: " << top->w_data_axi4 << std::endl;
							// 	char ch;
							// 	unsigned long int offset = top->addr_axi4 - UART_BASE;
							// 	if(offset >=0 && offset < 8) ch = ( (top->w_data_axi4) >> (offset*8) ) % 256;
							// 	else if ( offset>=8 && offset<=10 ) ch = ( (top->w_data_axi4) >> ( (offset-8)*8) ) % 256;
							// 	std::cout << "UART x : " << ch << std::endl;
							// 	// printf("%c", ch);
							// 	std::cout << "UART x END" << std::endl;
							// }
							top->io_master_bvalid = 0;
							mem_access_delay -= 1;
						}
					}
					else {
						top->io_master_rvalid = 0;
						top->io_master_bvalid = 0;
					}

					// mtime += 1; // Uptime "mtime" register at every posedge clk
					if(mtime_div == 0){
						// mtime = 0;
						mtime += 1;
						mtime_div = 0;
					}
					else mtime_div += 1;
				}
			}
			
			// if( main_time % CLK_CYCLE == CLK_POSEDGE+1 && top->mac_ok==1){
			// 	pc_hist[3] = pc_hist[2];
			// 	pc_hist[2] = pc_hist[1];
			// 	pc_hist[1] = pc_hist[0];
			// 	pc_hist[0] = top->addr_axi4;
			// 	if(pc_hist[0]==pc_hist[2] && pc_hist[1]==pc_hist[3]) pc_hist_count += 1;
			// 	else pc_hist_count = 0;
			// 	if(pc_hist_count == 100){
			// 		is_stop = 1;
			// 		std::cout << "\nis_stop" << std::endl;
			// 		break;
			// 	} 
			// }

			top->eval();
			// tfp->dump(main_time);
			// if(main_time  < 9999) tfp->dump(main_time);
			main_time++;			
			// if(top->io_master_arvalid && (top->io_master_araddr == 0x800fff88) ) std::cout << "rrrrr" << std::endl;
			// if(top->io_master_awvalid && (top->io_master_awaddr == 0x800fff88) ) std::cout << "wwwww" << std::endl;
			// if(main_time%10000000 == 0) std::cout << "\nSim time: " << main_time << std::endl;

			// if(top->is_x9 == 1) std::cout << main_time << " " << std::endl;
			// if(top->addr_axi4 == 0x80000e40) std::cout << "Event: " << main_time << std::endl;
		}

		// std::cout << "\nx10: " << top->value_x10 << std::endl;

#ifdef TRACE_PC
		pc_file.close();
#endif

		ofstream file_pc;
		file_pc.open("stop_pc.txt");
		if(is_stop==1) file_pc << pc_hist[0];
		else file_pc << 0;
		file_pc.close();

		// std::cout << "x10: " << top->value_x10 << std::endl;

	// std::cout << data_rom[]
			
	std::cout << "\n\n\nSim ended at time: " << main_time << "\nThe final PC is: " << top->io_master_araddr << std::endl;
	// std::cout << top->addr_axi4 << std::endl;

	// clean
	tfp->close();
	delete top;
	delete tfp;
	exit(0);
	return 0;
}
